package ddz.db.redis;

import ch.qos.logback.classic.Logger;
import com.kaka.util.ResourceUtils;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.*;
import redis.clients.jedis.exceptions.JedisException;

import java.io.*;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

public class JedisFactory {

    private final Logger logger = (Logger) LoggerFactory.getLogger(JedisFactory.class);

    JedisPool jedisPool;
    JedisCluster jedisCluster;
    IRedis universalRedis;
    int database = -1;

    private InputStream getConfig() {
        String path = ResourceUtils.getClassLoaderPath(JedisFactory.class);
        File file = new File(path + "/sys-config/redis.properties");
        InputStream is = null;
        if (!file.exists()) {
            is = ResourceUtils.getResourceAsStream("sys-config/redis.properties", JedisFactory.class);
            if (is == null) return null;
        } else {
            try {
                is = new FileInputStream(file);
            } catch (FileNotFoundException e) {
                logger.error(e.getLocalizedMessage(), e);
            }
        }
        return is;
    }

    private JedisFactory() {
        InputStream inputStream = getConfig();
        try {
            Properties props = new Properties();
            props.load(inputStream);

            int database = Integer.parseInt(props.getProperty("database"));
            long maxWaitMillis = Long.parseLong(props.getProperty("maxWaitMillis"));
            int maxTotals = Integer.parseInt(props.getProperty("maxTotals"));
            int maxIdle = Integer.parseInt(props.getProperty("maxIdle"));
            int minIdle = Integer.parseInt(props.getProperty("minIdle"));
            JedisPoolConfig config = new JedisPoolConfig();
            //控制一个pool可分配多少个jedis实例，通过pool.getResource()来获取；
            //如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
            config.setMaxTotal(maxTotals);
            //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
            config.setMaxIdle(maxIdle);
            config.setMinIdle(minIdle);
            //表示当borrow(引入)一个jedis实例时，最大的等待时间，如果超过等待时间，则直接抛出JedisConnectionException；
            config.setMaxWaitMillis(maxWaitMillis);

            String host = props.getProperty("host");
            String[] hosts = host.split(",|;");
            Set<String> hostSet = new HashSet<>(hosts.length);
            for (String s : hosts) {
                String ss = s.replaceAll(" ", "");
                hostSet.add(ss);
            }
            hosts = new String[hostSet.size()];
            hostSet.toArray(hosts);
            if (hosts.length == 1) {
                host = hosts[0];
                String[] parts = host.split(":");
                String ip = parts[0];
                int port = Integer.parseInt(parts[1]);
                String password = props.getProperty("password");

                this.database = database;

                //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
                config.setTestOnBorrow(false);
                config.setTestOnReturn(false);
                jedisPool = new JedisPool(config, ip, port, Protocol.DEFAULT_TIMEOUT, password, database);
                universalRedis = new AloneRedis();
                return;
            }
            Set<HostAndPort> nodes = new HashSet<>();
            for (String s : hosts) {
                String[] parts = s.split(":");
                String ip = parts[0];
                int port = Integer.parseInt(parts[1]);
                nodes.add(new HostAndPort(ip, port));
            }
            jedisCluster = new JedisCluster(nodes, config);
            //jedisCluster = new JedisCluster(nodes, 2000, 2000, 20, "", config);
            universalRedis = new ClusterRedis();
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.error(e.getLocalizedMessage(), e);
                }
            }
        }
    }

    private final static JedisFactory factory = new JedisFactory();

    public final static JedisFactory getFactory() {
        return factory;
    }

    public JedisCommands getJedisCommands() {
        if (jedisPool != null) {
            return getJedis();
        }
        if (jedisCluster != null) {
            return jedisCluster;
        }
        return null;
    }

    /**
     * 获取对象
     *
     * @return
     * @throws JedisException
     */
    public Jedis getJedis() throws JedisException {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
        } catch (JedisException e) {
            if (jedis != null) {
                jedis.close();
            }
            throw e;
        }
        return jedis;
    }

    public JedisCluster getJedisCluster() {
        return jedisCluster;
    }

    public void close(Object jedis) {
        if (jedis instanceof Jedis) {
            ((Jedis) jedis).close();
        } else if (jedis instanceof JedisCluster) {
        }
    }

    public void destroy() {
        try {
            if (jedisPool != null) {
                jedisPool.close();
                jedisPool.destroy();
            }
            if (jedisCluster != null) {
                jedisCluster.close();
            }
        } catch (Exception ex) {
        }
    }

    public IRedis getUniversalRedis() {
        return universalRedis;
    }

}
